import os
import re
import requests
from urllib.parse import urljoin
from glob import glob
from tqdm import tqdm
import subprocess

class M3U8Downloader:


    def __init__(self, m3u8_url, output_file='output.mp4', temp_dir='ts_temp'):
        self.m3u8_url = m3u8_url
        self.output_file = output_file
        self.temp_dir = temp_dir
        self.base_url = self._get_base_url(m3u8_url)
        self.ts_urls = []
        
        if not os.path.exists(temp_dir):
            os.makedirs(temp_dir)

    def _get_base_url(self, url):
        """获取基础URL，用于拼接相对路径的TS文件"""
        return url.rsplit('/', 1)[0] + '/'

    def _parse_m3u8(self):
        """解析M3U8文件，获取所有TS文件链接"""
        try:
            response = requests.get(self.m3u8_url)
            response.raise_for_status()
            content = response.text
            
            # 提取所有.ts文件的链接
            lines = content.split('\n')
            ts_files = [line.strip() for line in lines if line.endswith('.ts')]
            
            # 处理相对路径
            self.ts_urls = [urljoin(self.base_url, ts) for ts in ts_files]
            
            # 如果没有找到TS文件，可能是二级M3U8
            if not ts_files and '#EXT-X-STREAM-INF' in content:
                print("发现二级M3U8文件，尝试解析...")
                match = re.search(r'RESOLUTION=\d+x(\d+).*\n(.+\.m3u8)', content)
                if match:
                    secondary_url = urljoin(self.base_url, match.group(2))
                    self.base_url = self._get_base_url(secondary_url)
                    response = requests.get(secondary_url)
                    content = response.text
                    lines = content.split('\n')
                    self.ts_urls = [urljoin(self.base_url, line.strip()) 
                                  for line in lines if line.endswith('.ts')]
            
            return len(self.ts_urls) > 0
        except Exception as e:
            print(f"解析M3U8文件失败: {e}")
            return False

    def _download_ts_files(self):
        """下载所有TS文件"""
        if not self.ts_urls:
            print("没有可下载的TS文件")
            return False
            
        print(f"开始下载 {len(self.ts_urls)} 个TS文件...")
        
        for i, ts_url in enumerate(tqdm(self.ts_urls, desc="下载进度")):
            try:
                ts_file = os.path.join(self.temp_dir, f'segment_{i:04d}.ts')
                response = requests.get(ts_url, stream=True)
                response.raise_for_status()
                
                with open(ts_file, 'wb') as f:
                    for chunk in response.iter_content(chunk_size=1024*1024):  # 1MB
                        if chunk:
                            f.write(chunk)
            except Exception as e:
                print(f"下载 {ts_url} 失败: {e}")
                return False
                
        return True

    def _merge_with_ffmpeg(self):
        """使用ffmpeg合并TS文件"""
        try:
            # 获取按数字顺序排序的TS文件
            ts_files = sorted(glob(os.path.join(self.temp_dir, '*.ts')))
            
            # 创建文件列表
            list_file = os.path.join(self.temp_dir, 'file_list.txt')
            with open(list_file, 'w') as f:
                for ts_file in ts_files:
                    f.write(f"file '{os.path.basename(ts_file)}'\n")
            
            # 使用ffmpeg合并
            cmd = [
                'ffmpeg',
                '-f', 'concat',
                '-safe', '0',
                '-i', list_file,
                '-c', 'copy',
                '-bsf:a', 'aac_adtstoasc',  # 修复可能的AAC音频问题
                self.output_file
            ]
            
            subprocess.run(cmd, check=True)
            print(f"合并完成，输出文件: {self.output_file}")
            return True
        except subprocess.CalledProcessError as e:
            print(f"ffmpeg合并失败: {e}")
            return False
        except Exception as e:
            print(f"合并过程中出错: {e}")
            return False

    def download(self):
        """执行下载和合并流程"""
        if not self._parse_m3u8():
            return False
            
        if not self._download_ts_files():
            return False
            
        if not self._merge_with_ffmpeg():
            return False
            
        # 清理临时文件
        self._cleanup()
        return True

    def _cleanup(self):
        """清理临时文件"""
        for f in glob(os.path.join(self.temp_dir, '*.ts')):
            os.remove(f)
        list_file = os.path.join(self.temp_dir, 'file_list.txt')
        if os.path.exists(list_file):
            os.remove(list_file)
        print("已清理临时文件")

def download_ts_files(base_url):
   
    try:
        header={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0"}
        response = requests.get(base_url, stream=True)
        html = response.text
        m3u8=re.findall(r'(https?://[^\s]+?\.m3u8)',html)
        return m3u8
    except Exception as e:
            print(f"网址读取M3U8失败: {e}")
            return "null"
# 使用示例
if __name__ == "__main__":
    # 替换为实际的M3U8 URL
    html ="https://m.hn-younn.com/c/18803-3-39.html"

    m3u8_url = download_ts_files(html)#"https://yzzy.play-cdn7.com/20220720/6881_15fb18fd/index.m3u8"
    m3u8 = m3u8_url[0]
    print(m3u8)
    
    output_file = "40.mp4"
    
    downloader = M3U8Downloader(m3u8, output_file)
    if downloader.download():
        print("视频下载并合并成功！")
    else:
        print("视频下载失败")